#include "TcpConnection.h"
#include "EventLoop.h"

#include <sstream>

using std::ostringstream;
using std::cerr;

TcpConnection::TcpConnection(int fd, EventLoop *loop)
: _socketIO(fd)
, _socket(fd)
, _lAddr(getLocalAddr())
, _pAddr(getPeerAddr())
, _loop(loop)
{}

TcpConnection::~TcpConnection()
{
}

void TcpConnection::send(const string &msg)
{
    _socketIO.writen(msg.c_str(), msg.size());
}

string TcpConnection::receive()
{
    char buf[1024] = {0};
    _socketIO.readLine(buf, sizeof(buf));
    return string(buf);
}

string TcpConnection::toString()
{
    ostringstream oss;
    oss << "[" << _lAddr.ip() << ":" << _lAddr.port() << "-->"
        << _pAddr.ip() << ":" << _pAddr.port() << "]";
    return oss.str();
}

bool TcpConnection::isClose() const
{
    char buf[8];
    return (::recv(_socket.fd(), buf, sizeof(buf), MSG_PEEK) == 0);
}

InetAddr TcpConnection::getLocalAddr()
{
    struct sockaddr_in laddr;
    socklen_t len = sizeof(struct sockaddr);
    int ret = ::getsockname(_socket.fd(), (struct sockaddr*)&laddr, &len);
    if(ret < 0)
    {
        cerr << "getsockname\n";
    }
    return InetAddr(laddr);
}

InetAddr TcpConnection::getPeerAddr()
{
    struct sockaddr_in paddr;
    socklen_t len = sizeof(struct sockaddr);
    int ret = ::getpeername(_socket.fd(), (struct sockaddr*)&paddr, &len);
    if(ret < 0)
    {
        cerr << "getpeername\n";
    }
    return InetAddr(paddr);
}

void TcpConnection::setNewConnectionCallback(const TcpConnectionCallback &cb)
{
    _onNewConnection = cb;
}

void TcpConnection::setMessageCallback(const TcpConnectionCallback &cb)
{
    _onMessage = cb;
}

void TcpConnection::setCloseCallback(const TcpConnectionCallback &cb)
{
    _onClose = cb;
}

void TcpConnection::handleNewConnection()
{
    if(_onNewConnection)
    {
        _onNewConnection(shared_from_this());
    }
    else
    {
        cerr << "_onNewConnection == nullptr.\n";
    }
}

void TcpConnection::handleMessage()
{
    if(_onMessage)
    {
        _onMessage(shared_from_this());
    }
    else
    {
        cerr << "_onMessage == nullptr.\n";
    }
}

void TcpConnection::handleClose()
{
    if(_onClose)
    {
        _onClose(shared_from_this());
    }
    else
    {
        cerr << "_onClose == nullptr.\n";
    }
}

void TcpConnection::sendInLoop(const string &msg)
{
    if(_loop)
    {
        _loop->runInLoop(std::bind(TcpConnection::send, this, msg));
    }
}